/' Copyright (c) 2007 Scott Lembcke
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 '/

extern "C"

type cpBodyVelocityFunc as sub cdecl( byval as cpBody_ ptr, byval as cpVect, byval as cpFloat, byval as cpFloat )
type cpBodyPositionFunc as sub cdecl( byval as cpBody_ ptr, byval as cpFloat )

extern cpBodyUpdateVelocityDefault alias "cpBodyUpdateVelocityDefault" as cpBodyVelocityFunc
extern cpBodyUpdatePositionDefault alias "cpBodyUpdatePositionDefault" as cpBodyPositionFunc

'' Structure to hold information about the contact graph components
'' when putting groups of objects to sleep.
'' No interesting user accessible fields.
type cpComponentNode
	as cpBody_ ptr	root
	as cpBody_ ptr	next
	as cpFloat		idleTime
end type

type cpBody
	'' Function that is called to integrate the body's velocity. (Defaults to cpBodyUpdateVelocity)
	as cpBodyVelocityFunc	velocity_func
	
	'' Function that is called to integrate the body's position. (Defaults to cpBodyUpdatePosition)
	as cpBodyPositionFunc	position_func
	
	'' Mass of the body.
	'' Must agree with cpBody.m_inv! Use cpBodySetMass() when changing the mass for this reason.
	as cpFloat				m
	'' Mass inverse.
	as cpFloat				m_inv
	
	'' Moment of inertia of the body.
	'' Must agree with cpBody.i_inv! Use cpBodySetMoment() when changing the moment for this reason.
	as cpFloat				i
	'' Moment of inertia inverse.
	as cpFloat				i_inv
	
	'' Position of the rigid body's center of gravity.
	as cpVect				p
	'' Velocity of the rigid body's center of gravity.
	as cpVect				v
	'' Force acting on the rigid body's center of gravity.
	as cpVect				f
	
	'' Rotation of the body around it's center of gravity in radians.
	'' Must agree with cpBody.rot! Use cpBodySetAngle() when changing the angle for this reason.
	as cpFloat				a
	'' Angular velocity of the body around it's center of gravity in radians/second.
	as cpFloat				w
	'' Torque applied to the body around it's center of gravity.
	as cpFloat				t
	
	'' Cached unit length vector representing the angle of the body.
	'' Used for fast rotations using cpvrotate().
	as cpVect				rot
	
	'' User definable data pointer.
	'' Generally this points to your the game object class so you can access it
	'' when given a cpBody reference in a callback.
	as cpDataPointer		data
	
	'' Maximum velocity allowed when updating the velocity.
	as cpFloat				v_limit
	'' Maximum rotational rate (in radians/second) allowed when updating the angular velocity.
	as cpFloat				w_limit
	
	'' * FreeBASIC Note: The following variables are private - DO NOT MODIFY THEM DIRECTLY!!!!
	as cpVect				v_bias
	as cpFloat				w_bias
	
	as cpSpace_ ptr			space
	
	as cpShape_ ptr			shapeList
	as cpArbiter_ ptr		arbiterList
	as cpConstraint_ ptr	constraintList
	
	as cpComponentNode		node
end type

'' Basic allocation/destruction functions
declare function cpBodyAlloc () as cpBody ptr
declare function cpBodyInit ( byval as cpBody ptr, byval as cpFloat, byval as cpFloat ) as cpBody ptr
declare function cpBodyNew ( byval as cpFloat, byval as cpFloat ) as cpBody ptr

'' Initialize a static cpBody.
declare function cpBodyInitStatic ( byval as cpBody ptr ) as cpBody ptr
'' Allocate and initialize a static cpBody.
declare function cpBodyNewStatic () as cpBody ptr

'' Destroy a cpBody.
declare sub cpBodyDestroy ( byval as cpBody ptr )
'' Destroy and free a cpBody.
declare sub cpBodyFree ( byval as cpBody ptr )

'' Check that the properties of a body is sane. (Only in debug mode)
#ifdef NDEBUG
	#define	cpBodyAssertSane(body)
#else
	declare sub cpBodySanityCheck ( byval as cpBody ptr )
	#define	cpBodyAssertSane(body) cpBodySanityCheck(body)
#endif

'' Wake up a sleeping or idle body.
declare sub cpBodyActivate ( byval as cpBody ptr )
'' Wake up any sleeping or idle bodies touching a static body.
declare sub cpBodyActivateStatic ( byval as cpBody ptr, byval as cpShape_ ptr )

'' Force a body to sleep
'' defined in cpSpaceComponenet.c
declare sub cpBodySleep ( byval as cpBody ptr )
declare sub cpBodySleepWithGroup ( byval as cpBody, byval as cpBody ptr )

function cpBodyIsSleeping cdecl( byval body as const cpBody ptr ) as cpBool
	return ( body->node.next <> ( cptr(cpBody ptr, 0) ) )
end function

function cpBodyIsStatic cdecl( byval body as const cpBody ptr ) as cpBool
	return ( body->node.idleTime = INFINITY )
end function

function cpBodyIsRogue cdecl( byval body as const cpBody ptr ) as cpBool
	return ( body->space = (cptr( cpSpace_ ptr, 0) ) )
end function

#define CP_DefineBodyStructGetter(t, member, n) function cpBodyGet##n cdecl( byval body as const cpBody ptr ) as t: return body->member : end function

#macro CP_DefineBodyStructSetter(t, member, n)
sub cpBodySet##n cdecl( byval body as cpBody ptr, byval value as const t )
	cpBodyActivate(body)
	cpBodyAssertSane(body)
	body->member = value
end sub
#endmacro

#macro CP_DefineBodyStructProperty(t, member, n)
CP_DefineBodyStructGetter(t, member, n)
CP_DefineBodyStructSetter(t, member, n)
#endmacro

CP_DefineBodyStructGetter(cpFloat, m, Mass)
'' Set the mass of a body.
declare sub cpBodySetMass ( byval as cpBody ptr, byval as cpFloat )

CP_DefineBodyStructGetter(cpFloat, i, Moment)
'' Set the moment of a body.
declare sub cpBodySetMoment( byval as cpBody ptr, byval as cpFloat )

CP_DefineBodyStructGetter(cpVect, p, Pos)
'' Set the position of a body.
declare sub cpBodySetPos ( byval as cpBody ptr, byval as cpVect )
CP_DefineBodyStructProperty(cpVect, v, Vel)
CP_DefineBodyStructProperty(cpVect, f, Force)
CP_DefineBodyStructGetter(cpFloat, a, Angle)
'' Set the angle of a body.
declare sub cpBodySetAngle cdecl alias "cpBodySetAngle" ( byval as cpBody ptr, byval as cpFloat )
CP_DefineBodyStructProperty(cpFloat, w, AngVel)
CP_DefineBodyStructProperty(cpFloat, t, Torque)
CP_DefineBodyStructGetter(cpVect, rot, Rot)
CP_DefineBodyStructProperty(cpFloat, v_limit, VelLimit)
CP_DefineBodyStructProperty(cpFloat, w_limit, AngVelLimit)
CP_DefineBodyStructProperty(cpDataPointer, data, UserData)

'' Default Integration functions.
declare sub cpBodyUpdateVelocity ( byval as cpBody ptr, byval as cpVect, byval as cpFloat, byval as cpFloat )
declare sub cpBodyUpdatePosition ( byval as cpBody ptr, byval as cpFloat )

'' Convert body relative/local coordinates to absolute/world coordinates.
function cpBodyLocal2World cdecl( byval body as const cpBody ptr, byval v as const cpVect ) as cpVect
	return cpvadd( body->p, cpvrotate( v, body->rot ) )
end function

'' Convert body absolute/world coordinates to  relative/local coordinates.
function cpBodyWorld2Local cdecl( byval body as const cpBody ptr, byval v as const cpVect ) as cpVect
	return cpvunrotate( cpvsub( v, body->p ), body->rot )
end function

'' Set the forces and torque or a body to zero.
declare sub cpBodyResetForces ( byval as cpBody ptr )
'' Apply an force (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
declare sub cpBodyApplyForce ( byval as cpBody ptr, byval as const cpVect, byval as const cpVect )
'' Apply an impulse (in world coordinates) to the body at a point relative to the center of gravity (also in world coordinates).
declare sub cpBodyApplyImpulse ( byval as cpBody ptr, byval as const cpVect, byval as const cpVect )

'' Get the kinetic energy of a body.
function cpBodyKineticEnergy cdecl( byval body as const cpBody ptr ) as cpFloat
	'' Need to do some fudging to avoid NaNs
	dim as cpFloat vsq = cpvdot( body->v, body->v )
	dim as cpFloat wsq = body->w * body->w
	return iif( vsq, vsq * body->m, 0.0 ) + iif( wsq, wsq * body->i, 0.0 )
end function

'' Body/shape iterator callback function type.
type cpBodyShapeIteratorFunc as sub cdecl( byval as cpBody ptr, byval as cpShape_ ptr, byval as any ptr )
'' Call @c func once for each shape attached to @c body and added to the space.
declare sub cpBodyEachShape ( byval as cpBody ptr, byval as cpBodyShapeIteratorFunc, byval as any ptr )

'' Body/constraint iterator callback function type. 
type cpBodyConstraintIteratorFunc as sub cdecl( byval as cpBody ptr, byval as cpConstraint_ ptr, byval as any ptr )
'' Call @c func once for each constraint attached to @c body and added to the space.
declare sub cpBodyEachConstraint ( byval as cpBody ptr, byval as cpBodyconstraintIteratorFunc, byval as any ptr )

'' Body/arbiter iterator callback function type. 
type cpBodyArbiterIteratorFunc as sub cdecl( byval as cpBody ptr, byval as cpArbiter_ ptr, byval as any ptr )
'' Call @c func once for each arbiter that is currently active on the body.
declare sub cpBodyEachArbiter ( byval as cpBody ptr, byval as cpBodyArbiterIteratorFunc, byval as any ptr )

end extern
